/*
 * 
 */

package corejs.stmt;

import corejs.expr.Expression;

import corejs.expr.ExpressionVisitor;

import corejs.rt.FlowBreakException;
import corejs.rt.FlowContinueException;
import corejs.rt.FlowReturnException;

/**
 *
 * @author pengyu
 */
public abstract class Loop extends Statement {
   
   protected final Expression _test;
   protected final Statement _stmt;

   /**
    * 
    * @param test
    * @param stmt 
    */
   public Loop(final Expression test, final Statement stmt) {
      _test = test;
      _stmt = stmt;
   }

   @Override
   public void accept(final StatementVisitor visitor) {
      visitor.visitLoop(this);
   }

   /**
    * 
    * @param ev
    * @param sv 
    */
   public void loop(final ExpressionVisitor ev, final StatementVisitor sv) {
      beforeLoop(ev);
      while (test(ev)) {
         try {
            _stmt.accept(sv);
         }
         catch (final FlowBreakException b){
            break;
         }
         catch (final FlowReturnException r) {
            throw r;
         }
         catch (final FlowContinueException c) {
         }

         if (afterEachIteration(ev)) {
            break;
         }
      }
   }

   /**
    * 
    * @param v
    * @return 
    */
   protected boolean test(final ExpressionVisitor v) {
      return null == _test ? true : _test.accept(v).toBool().isTrue();
   }

   /**
    * 
    * @param v 
    */
   protected void beforeLoop(final ExpressionVisitor v) {}

   /**
    * 
    * @param v 
    */
   protected boolean afterEachIteration(final ExpressionVisitor v) {
      return false;
   }

}
